package table;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.emf.ecore.EObject;

import utils.Utils;

public class TableParser {
	private InstanceParser instance_parser;
	private String[] types;

	class Operation {
		int[] src;
		boolean more_src = false;
		String relation;
		int[] dst;
		boolean more_dst = false;
	
		public String toString() {
			String s = "";
			s += "ADD [" + src[0];
			for (int i = 1; i < src.length; i++) {
				s += " " + src[i];
			}
			if (more_src)
				s += " +";
			s += "] -> " + relation + " -> [" + dst[0];
			for (int i = 1; i < dst.length; i++) {
				s += " " + dst[i];
			}
			if (more_dst)
				s += " +";
			s += "]";
			return s;
		}
	}
	private Vector<Operation> operations;

	public TableParser(InstanceParser i) {
		instance_parser = i;
		types = null;
	}

	public void loadTable(String file) {
		System.out.println("=====> " + file + " <=====");
		try {
			BufferedReader br = new BufferedReader(new FileReader(file));
			String line;
			while ((line = br.readLine()) != null) {
				loadLine(instance_parser, line);
			}
			br.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private Operation createOperation(String[] left, String ref, String[] right) {
		Operation operation = new Operation();
		
		operation.relation = ref;
		
		if (left[left.length-1].equals("+")) {
			operation.more_src = true;
			operation.src = new int[left.length-1];
		}
		else {
			operation.src = new int[left.length];
		}
		
		if (right[right.length-1].equals("+")) {
			operation.more_dst = true;
			operation.dst = new int[right.length-1];
		}
		else {
			operation.dst = new int[right.length];
		}
		
		for (int i = 0; i < operation.src.length; i++) {
			operation.src[i] = Integer.parseInt(left[i]);
		}
		
		for (int i = 0; i < operation.dst.length; i++) {
			operation.dst[i] = Integer.parseInt(right[i]);
		}

		return operation;
	}
	
	void loadLine(InstanceParser parser, String line) {
		Pattern pType = Pattern.compile("%\\s*TYPES\\s+(.*)");
		Pattern pAdd = Pattern.compile("%\\s*ADD\\s+\\[(.*)\\]\\s*->\\s*(\\w+)\\s*->\\s*\\[(.*)\\]");
		Pattern pComment = Pattern.compile("%%.*");
		Pattern pEmpty = Pattern.compile("\\s*");
		
		Matcher m;
		
		//System.out.println("\nline: " + line);
		
		// cas d une declaration de type
		m = pType.matcher(line);
		if (m.matches()) {
			types = m.group(1).split("\\s+");
			System.out.println("> TYPES " + m.group(1));
			operations = new Vector<Operation>();
			return;
		}
		
		// cas d un add
		m = pAdd.matcher(line);
		if (m.matches()) {
			Operation operation = createOperation(m.group(1).split("\\s+"), m.group(2), m.group(3).split("\\s+"));
			System.out.println("> " + operation);
			operations.add(operation);
			return;
		}
		
		
		// cas d un commentaire
		m = pComment.matcher(line);
		if (m.matches()) {
			System.out.println("> Comments");
			return;
		}
		
		// ligne vide
		m = pEmpty.matcher(line);
		if (m.matches()) {
			System.out.println(">");
			return ;
		}
		// on applique toutes les operations
		System.out.println("> " + line);
		applyAll(line.split("\\s+"));
	}
	
	private void applyAll(String[] param) {
		for (Operation operation: operations) {
			apply(operation, param);
		}
	}
	
	private void apply(Operation operation, String[] param) {
		int src_length = (operation.more_src)?param.length-operation.src[0]:operation.src.length;
		int dst_length = (operation.more_dst)?param.length-operation.dst[0]:operation.dst.length;

		int src_id = -1;
		for (int i = 0; i < src_length; i++) {
			String src_type = (i < operation.src.length)?types[operation.src[i]]:types[types.length-1];
			src_id = (i < operation.src.length)?operation.src[i]:src_id+1;
			
			String src_path;
			if (src_type.equals("*")) {
				src_path = param[src_id];
			}
			else if (src_type.charAt(src_type.length()-1) == ')') {
				src_path = src_type.substring(0, src_type.length()-1) + "=" + param[src_id] + ")";
			}
			else {
				src_path = src_type + "[" + param[src_id] + "]";
			}

			System.out.println("SRC_PATH > " + src_path);
			EObject src = Utils.getObject(instance_parser.getRoot(), src_path, instance_parser.getFactories());
			System.out.println("SRC > " + src);
			
			int dst_id = -1;
			for (int j = 0; j < dst_length; j++) {
				String dst_type = (j < operation.dst.length)?types[operation.dst[j]]:types[types.length-1];
				dst_id = (j < operation.dst.length)?operation.dst[j]:dst_id+1;
				
				// Attribut
				if (Utils.isAttribute(src.eClass(), operation.relation)) {
					System.out.println("===> Attribute");
					if (dst_id >= param.length)
						Utils.setAttribute(src, operation.relation, null, instance_parser.getFactories());
					else
						Utils.setAttribute(src, operation.relation, param[dst_id], instance_parser.getFactories());
				}
				// Reference
				else {
					System.out.println("===> Reference");
					String dst_path;
					
					if (dst_type.equals("*")) {
						dst_path = param[dst_id];
					}
					else if (dst_type.charAt(dst_type.length()-1) == ')') {
						dst_path = dst_type.substring(0, dst_type.length()-1) + "=" + param[dst_id] + ")";
					}
					else {
						dst_path = dst_type + "[" + param[dst_id] + "]";
					}

					EObject dst = Utils.getObject(instance_parser.getRoot(), dst_path, instance_parser.getFactories());
				
					Utils.setReference(src, operation.relation, dst);
				}
			}
		}
	}
}
